<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>条形码生成器 - 综合版</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.5/dist/JsBarcode.all.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.6.1/canvg.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
    <style>
        body { background-color: #f8f9fa; font-family: 'Arial', sans-serif; }
        .container { max-width: 800px; margin-top: 50px; }
        .card { border: none; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); }
        .card-header { background-color: #007bff; color: white; font-size: 1.5rem; font-weight: bold; }
        .file-input { margin-bottom: 20px; }
        .btn-primary { background-color: #007bff; border: none; }
        .btn-primary:hover { background-color: #0056b3; }
        .btn-success { background-color: #28a745; border: none; }
        .btn-success:hover { background-color: #218838; }
        #barcode-preview { margin-top: 20px; text-align: center; }
        .barcode-item { margin-bottom: 20px; border: 1px solid #ddd; padding: 10px; background-color: white; border-radius: 5px; }
        .loading { display: none; text-align: center; margin-top: 20px; }
    </style>
</head>
<body>
    <div class="container">
        <div class="card">
            <div class="card-header text-center"><i class="fas fa-barcode"></i> 条形码生成器 - 综合版</div>
            <div class="card-body">
                <div class="file-input">
                    <label for="file-input" class="form-label">上传表格文件 (.csv, .xlsx, .xls)</label>
                    <input type="file" id="file-input" class="form-control" accept=".csv, .xlsx, .xls" />
                    <button class="btn btn-primary mt-2" onclick="importFromFile()"><i class="fas fa-upload"></i> 从表格导入</button>
                </div>
                <div class="mb-3">
                    <label for="barcode-data" class="form-label">输入条形码数据（每行一个，使用 / 表示文件夹层级）</label>
                    <textarea id="barcode-data" class="form-control" rows="4" placeholder="例如：folder1/123456"></textarea>
                </div>
                <div class="mb-3">
                    <label for="mode-select" class="form-label">选择生成模式</label>
                    <select id="mode-select" class="form-select">
                        <option value="normal">普通模式</option>
                        <option value="weight+0.5">重量加0.5</option>
                        <option value="weight+1">重量加1</option>
                        <option value="weight+size">重量加尺寸</option>
                    </select>
                </div>
                <div class="d-grid gap-2 d-md-flex justify-content-md-center">
                    <button class="btn btn-primary" onclick="generateBarcode()"><i class="fas fa-cogs"></i> 生成条形码</button>
                    <button class="btn btn-success" onclick="exportBarcodes()"><i class="fas fa-download"></i> 批量导出PNG</button>
                </div>
                <div class="loading" id="loading">
                    <div class="spinner-border text-primary" role="status"><span class="visually-hidden">加载中...</span></div>
                    <p class="mt-2">正在处理，请稍候...</p>
                </div>
                <div id="barcode-preview"></div>
            </div>
        </div>
    </div>

    <script>
        let barcodes = [];
        let fileName = "barcodes";

        function showLoading() { document.getElementById('loading').style.display = 'block'; }
        function hideLoading() { document.getElementById('loading').style.display = 'none'; }
        function clearData() {
            document.getElementById('barcode-data').value = '';
            document.getElementById('barcode-preview').innerHTML = '';
            barcodes = [];
        }

        function importFromFile() {
            const fileInput = document.getElementById('file-input');
            const file = fileInput.files[0];
            if (!file) { alert("请选择一个文件！"); return; }
            fileName = file.name.replace(/\.[^/.]+$/, "");
            showLoading();
            const reader = new FileReader();
            reader.onload = function (e) {
                const data = new Uint8Array(e.target.result);
                let workbook;
                try {
                    workbook = XLSX.read(data, { type: 'array' });
                } catch (error) {
                    alert("文件格式不支持或文件损坏！");
                    hideLoading();
                    return;
                }
                const firstSheetName = workbook.SheetNames[0];
                const worksheet = workbook.Sheets[firstSheetName];
                const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
                const textData = jsonData
                    .map(row => row
                        .filter(cell => cell !== null && cell !== undefined && cell.toString().trim() !== "")
                        .join('/')
                    )
                    .join('\n');
                document.getElementById('barcode-data').value = textData;
                hideLoading();
            };
            reader.readAsArrayBuffer(file);
        }

        function generateBarcode() {
            const inputData = document.getElementById('barcode-data').value;
            const lines = inputData.split('\n').filter(line => line.trim() !== '');
            const preview = document.getElementById('barcode-preview');
            const mode = document.getElementById('mode-select').value;
            preview.innerHTML = '';
            barcodes = [];
            showLoading();
            lines.forEach((line, index) => {
                const pathParts = line.split('/');
                let barcodeData = pathParts[0]; // 第一部分作为条形码数据

                // 根据选择的模式处理二级数值
                if (pathParts.length > 1) {
                    switch (mode) {
                        case 'weight+1':
                            if (!isNaN(pathParts[1])) {
                                const secondPart = parseFloat(pathParts[1]) + 1;
                                pathParts[1] = secondPart.toString();
                            }
                            break;
                        case 'weight+0.5':
                            if (!isNaN(pathParts[1])) {
                                const secondPart = parseFloat(pathParts[1]) + 0.5;
                                pathParts[1] = secondPart.toString();
                            }
                            break;
                        case 'weight+size':
                            if (pathParts.length > 2) {
                                pathParts[1] = `${pathParts[1]}kg${pathParts[2] ? `_${pathParts[2]}` : ''}`;
                            }
                            break;
                    }
                    line = pathParts.join('/'); // 重新拼接路径
                }

                const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
                svg.setAttribute('id', `barcode-${index}`);
                svg.setAttribute('class', 'barcode-item');
                preview.appendChild(svg);
                JsBarcode(svg, barcodeData, { format: "CODE128", displayValue: true, fontSize: 16, lineColor: "#000", width: 2, height: 100 });
                const svgString = new XMLSerializer().serializeToString(svg);
                barcodes.push({ path: line, svg: svgString, barcodeData: barcodeData });
            });
            hideLoading();
        }

        function svgToPng(svgString) {
            return new Promise((resolve) => {
                const canvas = document.createElement('canvas');
                const ctx = canvas.getContext('2d');
                const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
                const url = URL.createObjectURL(svgBlob);
                const img = new Image();
                img.onload = () => {
                    canvas.width = img.width;
                    canvas.height = img.height;
                    ctx.drawImage(img, 0, 0);
                    URL.revokeObjectURL(url);
                    canvas.toBlob((blob) => { resolve(blob); }, 'image/png');
                };
                img.src = url;
            });
        }

        async function exportBarcodes() {
            if (barcodes.length === 0) { alert("请先生成条形码！"); return; }
            showLoading();
            const zip = new JSZip();
            for (const barcode of barcodes) {
                const pathParts = barcode.path.split('/');
                let currentFolder = zip;
                if (pathParts.length > 1) {
                    const folderName = pathParts[1];
                    if (!currentFolder.folder(folderName)) {
                        currentFolder = currentFolder.folder(folderName);
                    } else {
                        currentFolder = currentFolder.folder(folderName);
                    }
                }
                const pngBlob = await svgToPng(barcode.svg);
                const filename = `${barcode.barcodeData}.png`;
                currentFolder.file(filename, pngBlob);
            }
            zip.generateAsync({ type: "blob" }).then((content) => {
                saveAs(content, `${fileName}.zip`);
                hideLoading();
                clearData();
            });
        }
    </script>
</body>
</html>